package com.by.course.manage;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.by.course.entity.base.BaseResult;
import com.by.course.entity.bo.*;
import com.by.course.entity.vo.schedule.req.*;
import com.by.course.entity.vo.schedule.resp.BaseScheduleDetailResultVO;
import com.by.course.entity.vo.schedule.resp.BaseScheduleResultVO;
import com.by.course.entity.vo.schedule.resp.BaseScheduledStudentResultVO;
import com.by.course.entity.vo.user.req.GetBaseUserVO;
import com.by.course.enums.CommonStatusEnum;
import com.by.course.enums.ErrEnum;
import com.by.course.enums.UserRoleEnum;
import com.by.course.execption.BusinessException;
import com.by.course.mapper.*;
import com.by.course.serivce.BaseScheduleService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class BaseCourseManager {

    private final static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");

    @Resource
    private BaseScheduleMapper baseScheduleMapper;

    @Resource
    private BaseScheduleService baseScheduleService;

    @Resource
    private BaseAppointmentMapper baseAppointmentMapper;

    @Resource
    private BaseLessonMapper baseLessonMapper;

    @Resource
    private BaseCourseMapper baseCourseMapper;

    @Resource
    private BaseUserBindMapper baseUserBindMapper;

    @Resource
    private BaseLessonReviewMapper baseLessonReviewMapper;

    @Resource
    private BaseUserMapper baseUserMapper;

    @Transactional(rollbackFor = Exception.class)
    public BaseResult<String> createSchedule(AddBaseScheduleVO vo) {
        List<BaseSchedule> scheduleBoList = new ArrayList<>();
        List<DayInfo> dayInfoList = vo.getDayInfoList();
        List<List<TimeInfo>> timeInfoList = vo.getTimeInfoList();
        for (int i = 0; i < timeInfoList.size(); i++) {
            DayInfo dayInfo = dayInfoList.get(i);
            List<TimeInfo> timeInfos = timeInfoList.get(i);
            for (TimeInfo timeInfo : timeInfos) {
                String[] split = timeInfo.getTimeArea().split("-");
                //  2025-03-11 06:00 转化为 LocalDateTime
                LocalDateTime starTime = LocalDateTime.parse(dayInfo.getYearMd() + " " + split[0], formatter);
                LocalDateTime endTime = LocalDateTime.parse(dayInfo.getYearMd() + " " + split[1], formatter);
                BaseSchedule baseSchedule = new BaseSchedule();
                baseSchedule.setLessonId(timeInfo.getLessonId());
                baseSchedule.setTeacherId(vo.getTeacherId());
                baseSchedule.setStartTime(starTime);
                baseSchedule.setEndTime(endTime);
                baseSchedule.setMaxStudents(timeInfo.getMaxStudents());
                baseSchedule.setId(timeInfo.getScheduleId());
                scheduleBoList.add(baseSchedule);
            }
        }

        List<Long> scheduleIdList = vo.getScheduleIdList();
        if (CollectionUtil.isEmpty(scheduleIdList)) {
            baseScheduleService.saveBatch(scheduleBoList);
        } else {
            List<BaseSchedule> updateList = new ArrayList<>();
            List<BaseSchedule> addList = new ArrayList<>();
            List<Long> newScheduleIdList = new ArrayList<>();
            for (BaseSchedule baseSchedule : scheduleBoList) {
                if (scheduleIdList.contains(baseSchedule.getId())) {
                    updateList.add(baseSchedule);
                    newScheduleIdList.add(baseSchedule.getId());
                } else {
                    addList.add(baseSchedule);
                }
            }
            if (CollUtil.isNotEmpty(addList)) {
                baseScheduleService.saveBatch(addList);
            }
            if (CollUtil.isNotEmpty(updateList)) {
                baseScheduleService.updateBatchById(updateList);
            }
            // 删除
            List<Long> deleteList = scheduleIdList.stream().filter(t -> !newScheduleIdList.contains(t)).collect(Collectors.toList());
            baseScheduleService.removeByIds(deleteList);
        }

        return BaseResult.builder().build();
    }

    public BaseResult<String> updateSchedule(UpdateBaseScheduleVO vo) {
        if (vo.getId() == null) {
            throw new BusinessException("课程ID不能为空", ErrEnum.SCHEDULE_ERR.getCode());
        }
        BaseSchedule baseSchedule = baseScheduleMapper.selectById(vo.getId());
        if (baseSchedule == null) {
            throw new BusinessException("课程不存在", ErrEnum.SCHEDULE_ERR.getCode());
        }
        if (vo.getMaxStudents() != null) {
            baseSchedule.setMaxStudents(vo.getMaxStudents());
        }
        if (vo.getStartTime() != null) {
            baseSchedule.setStartTime(vo.getStartTime());
        }
        if (vo.getEndTime() != null) {
            baseSchedule.setEndTime(vo.getEndTime());
        }
        baseScheduleMapper.updateByPrimaryKeySelective(baseSchedule);
        return BaseResult.builder().build();
    }


    public BaseResult<BaseScheduleResultVO> getScheduleByUserId(GetBaseScheduleVO vo) {
        if (vo.getTeacherId() == null) {
            throw new BusinessException("课程老师不能为空", ErrEnum.SCHEDULE_ERR.getCode());
        }
        BaseScheduleResultVO baseScheduleResultVO = new BaseScheduleResultVO();

        vo.setStartTime(LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0));
        vo.setEndTime(LocalDateTime.now().plusDays(7).withHour(0).withMinute(0).withSecond(0).withNano(0));

        List<BaseSchedule> baseScheduleList = baseScheduleMapper.selectBaseScheduleByUserId(vo.getTeacherId());
        List<BaseSchedule> filterScheduleList = baseScheduleList.stream()
                .filter(t -> t.getStartTime().isAfter(vo.getStartTime()) && t.getEndTime().isBefore(vo.getEndTime()))
                .collect(Collectors.toList());

        if (CollectionUtil.isEmpty(filterScheduleList)) {
            return new BaseResult.Builder<BaseScheduleResultVO>().setData(baseScheduleResultVO).build();
        }

        // 获取 lessonId - title 映射
        List<Long> lessonIdList = filterScheduleList.stream().map(BaseSchedule::getLessonId).collect(Collectors.toList());
        List<BaseLesson> baseLessons = baseLessonMapper.selectBatchIds(lessonIdList);
        Map<Long, BaseLesson> lessonMap = baseLessons.stream().collect(Collectors.toMap(BaseLesson::getId, t -> t));

        // 获取 courseId - courseName 映射
        List<Long> courseIdList = baseLessons.stream().map(BaseLesson::getCourseId).collect(Collectors.toList());
        List<BaseCourse> baseCourses = baseCourseMapper.selectBatchIds(courseIdList);
        Map<Long, BaseCourse> courseMap = baseCourses.stream().collect(Collectors.toMap(BaseCourse::getId, t -> t));

        // 获取预约的个数
        List<Long> scheduleIdList = filterScheduleList.stream().map(BaseSchedule::getId).collect(Collectors.toList());
        List<BaseAppointment> baseAppointmentList = baseAppointmentMapper.selectAppointmentByScheduleIdList(scheduleIdList);
        Map<Long, Map<Integer, Long>> appointmentMap = baseAppointmentList.stream()
                .collect(Collectors.groupingBy(BaseAppointment::getScheduleId, Collectors.groupingBy(BaseAppointment::getStatus, Collectors.counting())));

        // 按照7天进行划分，如果中间有空缺的时间段，需要补全空余的天数日期
        // 获取当前连续7天的日期列表
        List<String> dateList = new ArrayList<>();
        for (int i = 0; i < 7; i++) {
            dateList.add(LocalDateTime.now().plusDays(i).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        }

        Map<String, List<BaseSchedule>> resultMap = filterScheduleList.stream()
                .collect(Collectors.groupingBy(t -> t.getStartTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))));

        List<List<TimeInfo>> timeInfoList = new ArrayList<>();

        for (String time : dateList) {
            if (resultMap.containsKey(time)) {
                List<TimeInfo> timeInfos = new ArrayList<>();
                List<BaseSchedule> baseSchedules = resultMap.get(time);
                for (BaseSchedule baseSchedule : baseSchedules) {
                    TimeInfo timeInfo = new TimeInfo();
                    timeInfo.setLessonId(baseSchedule.getLessonId());
                    timeInfo.setTimeArea(baseSchedule.getStartTime().format(DateTimeFormatter.ofPattern("HH:mm")) + "-" + baseSchedule.getEndTime().format(DateTimeFormatter.ofPattern("HH:mm")));
                    timeInfo.setScheduleId(baseSchedule.getId());
                    timeInfo.setMaxStudents(baseSchedule.getMaxStudents());
                    timeInfo.setLessonTitle(lessonMap.get(baseSchedule.getLessonId()).getTitle());
                    timeInfo.setCourseName(courseMap.get(lessonMap.get(baseSchedule.getLessonId()).getCourseId()).getName());
                    timeInfo.setCourseId(lessonMap.get(baseSchedule.getLessonId()).getCourseId());
                    Map<Integer, Long> statusCountMap = appointmentMap.get(baseSchedule.getId());
                    if (statusCountMap != null) {
                        Long aLong = statusCountMap.get(CommonStatusEnum.CLOSE.getCode());
                        if (aLong != null) {
                            timeInfo.setAppointments(statusCountMap.size() - aLong.intValue());
                        } else {
                            timeInfo.setAppointments(statusCountMap.size());
                        }
                    } else {
                        timeInfo.setAppointments(0);
                    }
                    timeInfos.add(timeInfo);
                }
                timeInfoList.add(timeInfos);
            } else {
                timeInfoList.add(new ArrayList<>());
            }
        }

        baseScheduleResultVO.setTimeInfoList(timeInfoList);
        baseScheduleResultVO.setScheduleIdList(scheduleIdList);
        return new BaseResult.Builder<BaseScheduleResultVO>().setData(baseScheduleResultVO).build();
    }

    public BaseResult<String> closeSchedule(DeleteBaseScheduleVO vo) {
        List<Long> scheduleIdList = baseAppointmentMapper.selectAppointmentIdByScheduleIdList(vo.getIdList());
        if (CollUtil.isNotEmpty(scheduleIdList)) {
            throw new BusinessException("该课程已有学生", ErrEnum.SCHEDULE_ERR.getCode());
        }
        baseScheduleMapper.deleteBatchIds(vo.getIdList());
        return BaseResult.builder().build();
    }

    public BaseResult<BaseScheduleResultVO> getScheduleByStudentId(GetBaseScheduleVO vo) {
        BaseScheduleResultVO baseScheduleResultVO = new BaseScheduleResultVO();

        List<Long> teacherIdList = baseUserBindMapper.selectTeacherListByUserId(vo.getStudentId());
        if (CollUtil.isEmpty(teacherIdList)) {
            return new BaseResult.Builder<BaseScheduleResultVO>().setData(baseScheduleResultVO).build();
        }

        vo.setStartTime(LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0));
        vo.setEndTime(LocalDateTime.now().plusDays(7).withHour(0).withMinute(0).withSecond(0).withNano(0));

        List<BaseSchedule> baseScheduleList = baseScheduleMapper.selectScheduleByTeacherIdList(teacherIdList);
        List<BaseSchedule> filterScheduleList = baseScheduleList.stream()
                .filter(t -> t.getStartTime().isAfter(vo.getStartTime()) && t.getEndTime().isBefore(vo.getEndTime()))
                .collect(Collectors.toList());

        if (CollectionUtil.isEmpty(filterScheduleList)) {
            return new BaseResult.Builder<BaseScheduleResultVO>().setData(baseScheduleResultVO).build();
        }

        // 获取 lessonId - title 映射
        List<Long> lessonIdList = filterScheduleList.stream().map(BaseSchedule::getLessonId).collect(Collectors.toList());
        List<BaseLesson> baseLessons = baseLessonMapper.selectBatchIds(lessonIdList);
        Map<Long, BaseLesson> lessonMap = baseLessons.stream().collect(Collectors.toMap(BaseLesson::getId, t -> t));

        // 获取 courseId - courseName 映射
        List<Long> courseIdList = baseLessons.stream().map(BaseLesson::getCourseId).collect(Collectors.toList());
        List<BaseCourse> baseCourses = baseCourseMapper.selectBatchIds(courseIdList);
        Map<Long, BaseCourse> courseMap = baseCourses.stream().collect(Collectors.toMap(BaseCourse::getId, t -> t));

        // 获取预约的个数
        List<Long> scheduleIdList = filterScheduleList.stream().map(BaseSchedule::getId).collect(Collectors.toList());
        List<BaseAppointment> baseAppointmentList = baseAppointmentMapper.selectAppointmentByScheduleIdList(scheduleIdList);
        Map<Long, Map<Integer, Long>> appointmentMap = baseAppointmentList.stream()
                .collect(Collectors.groupingBy(BaseAppointment::getScheduleId, Collectors.groupingBy(BaseAppointment::getStatus, Collectors.counting())));

        // 按照7天进行划分，如果中间有空缺的时间段，需要补全空余的天数日期
        // 获取当前连续7天的日期列表
        List<String> dateList = new ArrayList<>();
        for (int i = 0; i < 7; i++) {
            dateList.add(LocalDateTime.now().plusDays(i).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        }

        Map<String, List<BaseSchedule>> resultMap = filterScheduleList.stream()
                .collect(Collectors.groupingBy(t -> t.getStartTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))));

        List<List<TimeInfo>> timeInfoList = new ArrayList<>();

        List<BaseAppointment> baseAppointments = baseAppointmentMapper.selectAppointmentByUserId(vo.getStudentId());
        Map<Long, BaseAppointment> appointmentMapByUserId = baseAppointments.stream()
                .collect(Collectors.toMap(BaseAppointment::getScheduleId, t -> t));

        for (String time : dateList) {
            if (resultMap.containsKey(time)) {
                List<TimeInfo> timeInfos = new ArrayList<>();
                List<BaseSchedule> baseSchedules = resultMap.get(time);
                for (BaseSchedule baseSchedule : baseSchedules) {
                    TimeInfo timeInfo = new TimeInfo();
                    timeInfo.setLessonId(baseSchedule.getLessonId());
                    timeInfo.setTimeArea(baseSchedule.getStartTime().format(DateTimeFormatter.ofPattern("HH:mm")) + "-" + baseSchedule.getEndTime().format(DateTimeFormatter.ofPattern("HH:mm")));
                    timeInfo.setScheduleId(baseSchedule.getId());
                    timeInfo.setMaxStudents(baseSchedule.getMaxStudents());
                    timeInfo.setLessonTitle(lessonMap.get(baseSchedule.getLessonId()).getTitle());
                    timeInfo.setCourseName(courseMap.get(lessonMap.get(baseSchedule.getLessonId()).getCourseId()).getName());
                    timeInfo.setCourseId(lessonMap.get(baseSchedule.getLessonId()).getCourseId());
                    Map<Integer, Long> statusCountMap = appointmentMap.get(baseSchedule.getId());
                    if (statusCountMap != null) {
                        Long aLong = statusCountMap.get(CommonStatusEnum.CLOSE.getCode());
                        if (aLong != null) {
                            timeInfo.setAppointments(statusCountMap.size() - aLong.intValue());
                        } else {
                            timeInfo.setAppointments(statusCountMap.size());
                        }
                    } else {
                        timeInfo.setAppointments(0);
                    }
                    if (appointmentMapByUserId.containsKey(baseSchedule.getId())) {
                        BaseAppointment baseAppointment = appointmentMapByUserId.get(baseSchedule.getId());
                        timeInfo.setStatus(baseAppointment.getStatus());
                        timeInfo.setBaseAppointmentId(baseAppointment.getId());
                    }
                    timeInfos.add(timeInfo);
                }
                timeInfoList.add(timeInfos);
            } else {
                timeInfoList.add(new ArrayList<>());
            }
        }

        baseScheduleResultVO.setTimeInfoList(timeInfoList);
        baseScheduleResultVO.setScheduleIdList(scheduleIdList);
        return new BaseResult.Builder<BaseScheduleResultVO>().setData(baseScheduleResultVO).build();
    }

    public BaseResult<List<BaseScheduleDetailResultVO>> listSchedule(GetBaseScheduleVO vo) {
        if (vo.getTeacherId() == null) {
            throw new BusinessException("课程老师不能为空", ErrEnum.SCHEDULE_ERR.getCode());
        }
        vo.setStartTime(LocalDateTime.now().minusDays(30).withHour(0).withMinute(0).withSecond(0).withNano(0));
        List<BaseSchedule> baseScheduleList = baseScheduleMapper.selectBaseScheduleByUserId(vo.getTeacherId());
        if (CollectionUtil.isEmpty(baseScheduleList)) {
            return new BaseResult.Builder<List<BaseScheduleDetailResultVO>>().setData(null).build();
        }

        List<BaseSchedule> filterScheduleList = baseScheduleList.stream()
                .filter(t -> t.getStartTime().isAfter(vo.getStartTime()))
                .collect(Collectors.toList());

        if (CollectionUtil.isEmpty(filterScheduleList)) {
            return new BaseResult.Builder<List<BaseScheduleDetailResultVO>>().setData(null).build();
        }

        // 获取 lessonId - title 映射
        List<Long> lessonIdList = filterScheduleList.stream().map(BaseSchedule::getLessonId).collect(Collectors.toList());
        List<BaseLesson> baseLessons = baseLessonMapper.selectBatchIds(lessonIdList);
        Map<Long, BaseLesson> lessonMap = baseLessons.stream().collect(Collectors.toMap(BaseLesson::getId, t -> t));

        // 获取 courseId - courseName 映射
        List<Long> courseIdList = baseLessons.stream().map(BaseLesson::getCourseId).collect(Collectors.toList());
        List<BaseCourse> baseCourses = baseCourseMapper.selectBatchIds(courseIdList);
        Map<Long, BaseCourse> courseMap = baseCourses.stream().collect(Collectors.toMap(BaseCourse::getId, t -> t));

        // 获取预约的个数
        List<Long> scheduleIdList = filterScheduleList.stream().map(BaseSchedule::getId).collect(Collectors.toList());
        List<BaseAppointment> baseAppointmentList = baseAppointmentMapper.selectAppointmentByScheduleIdList(scheduleIdList);
        Map<Long, Map<Integer, Long>> appointmentMap = baseAppointmentList.stream()
                .collect(Collectors.groupingBy(BaseAppointment::getScheduleId, Collectors.groupingBy(BaseAppointment::getStatus, Collectors.counting())));

        List<BaseScheduleDetailResultVO> resultVoList = new ArrayList<>();
        for (BaseSchedule baseSchedule : filterScheduleList) {
            BaseScheduleDetailResultVO baseScheduleDetailResultVO = new BaseScheduleDetailResultVO();
            baseScheduleDetailResultVO.setScheduleId(baseSchedule.getId());
            baseScheduleDetailResultVO.setLessonId(baseSchedule.getLessonId());
            baseScheduleDetailResultVO.setMaxStudents(baseSchedule.getMaxStudents());
            baseScheduleDetailResultVO.setLessonTitle(lessonMap.get(baseSchedule.getLessonId()).getTitle());
            baseScheduleDetailResultVO.setCourseName(courseMap.get(lessonMap.get(baseSchedule.getLessonId()).getCourseId()).getName());
            baseScheduleDetailResultVO.setCourseId(lessonMap.get(baseSchedule.getLessonId()).getCourseId());
            Map<Integer, Long> statusCountMap = appointmentMap.get(baseSchedule.getId());
            if (statusCountMap != null) {
                Long aLong = statusCountMap.get(CommonStatusEnum.CLOSE.getCode());
                if (aLong != null) {
                    baseScheduleDetailResultVO.setAppointments(statusCountMap.size() - aLong.intValue());
                } else {
                    baseScheduleDetailResultVO.setAppointments(statusCountMap.size());
                }
            } else {
                baseScheduleDetailResultVO.setAppointments(0);
            }

            baseScheduleDetailResultVO.setStartTime(baseSchedule.getStartTime());
            baseScheduleDetailResultVO.setEndTime(baseSchedule.getEndTime());
            baseScheduleDetailResultVO.setStatus(baseSchedule.getStatus());
            resultVoList.add(baseScheduleDetailResultVO);
        }
        return new BaseResult.Builder<List<BaseScheduleDetailResultVO>>().setData(resultVoList).build();
    }

    public BaseResult<List<BaseScheduledStudentResultVO>> listStudentScheduler(GetBaseScheduleVO vo) {
        if (vo.getId() == null) {
            throw new BusinessException("排课ID不能为空", ErrEnum.SCHEDULE_ERR.getCode());
        }
        List<BaseAppointment> baseAppointments = baseAppointmentMapper.selectAppointmentByScheduleId(vo.getId());
        if (CollectionUtil.isEmpty(baseAppointments)) {
            return new BaseResult.Builder<List<BaseScheduledStudentResultVO>>().setData(null).build();
        }
        List<Long> studentIdList = baseAppointments.stream().map(BaseAppointment::getUserId).collect(Collectors.toList());
        List<BaseUser> baseUsers = baseUserMapper.selectBatchIds(studentIdList);
        Map<Long, BaseUser> userMap = baseUsers.stream().collect(Collectors.toMap(BaseUser::getId, t -> t));

        List<Long> baseAppointmentIdList = baseAppointments.stream().map(BaseAppointment::getId).collect(Collectors.toList());
        List<BaseLessonReview> baseLessonReviewList = baseLessonReviewMapper.selectReviewByAppointmentIdList(baseAppointmentIdList);
        Map<Long, BaseLessonReview> lessonReviewMap = baseLessonReviewList.stream().collect(Collectors.toMap(BaseLessonReview::getBaseAppointmentId, t -> t));

        List<BaseScheduledStudentResultVO> resultVoList = new ArrayList<>();
        for (BaseAppointment baseAppointment : baseAppointments) {
            if (baseAppointment.getStatus().equals(CommonStatusEnum.CLOSE.getCode())) {
                continue;
            }
            BaseScheduledStudentResultVO baseScheduledStudentResultVO = new BaseScheduledStudentResultVO();
            baseScheduledStudentResultVO.setBaseAppointmentId(baseAppointment.getId());
            baseScheduledStudentResultVO.setScheduleId(vo.getId());
            baseScheduledStudentResultVO.setUserId(baseAppointment.getUserId());
            baseScheduledStudentResultVO.setMobilePhone(userMap.get(baseAppointment.getUserId()).getMobilePhone());
            baseScheduledStudentResultVO.setNickName(userMap.get(baseAppointment.getUserId()).getNickName());
            baseScheduledStudentResultVO.setStatus(baseAppointment.getStatus());
            if (lessonReviewMap.get(baseAppointment.getId()) != null) {
                baseScheduledStudentResultVO.setBaseLessonReviewId(lessonReviewMap.get(baseAppointment.getId()).getId());
            }
            resultVoList.add(baseScheduledStudentResultVO);
        }
        return new BaseResult.Builder<List<BaseScheduledStudentResultVO>>().setData(resultVoList).build();
    }

    public BaseResult<List<BaseUser>> listStudent(GetBaseUserVO vo) {
        BaseUser baseUser = baseUserMapper.selectByPrimaryKey(vo.getId());

        if (!baseUser.getRole().equals(UserRoleEnum.TEACHER.getCode())) {
            throw new BusinessException("该用户不是老师", ErrEnum.USER_ERR.getCode());
        }

        List<Long> userIdList = baseUserBindMapper.selectUserListByTeacherId(vo.getId());
        if (CollectionUtil.isNotEmpty(userIdList)) {
            List<BaseUser> baseUsers = baseUserMapper.selectBatchIds(userIdList);
            if (CollectionUtil.isNotEmpty(baseUsers)) {
                return new BaseResult.Builder<List<BaseUser>>().setData(baseUsers).build();
            }
        }
        return new BaseResult.Builder<List<BaseUser>>().setData(null).build();
    }
}
